package com.djx.curator;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CuratorConnection {
/*
    static String MYIP = "192.168.15.132:2181";
    static String MYIPS = "192.168.15.132:2181,192.168.15.132:2182,192.168.15.132:2183";
    static int TIMEOUT = 9000;
    CuratorFramework curatorFramework;

    *//**
     * 创建curator 连接zookeeper
     *//*
    public void connection() {
        ExponentialBackoffRetry exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
        curatorFramework = CuratorFrameworkFactory.builder()    //创建连接对象
                .connectString(MYIPS)  //IP地址和端口号
                .sessionTimeoutMs(TIMEOUT) //客户端与服务器端会话超时时间
                *//**
                 * 重连策略  客户端与服务器端会话超时之后
                 * 1 retryPolicy(new RetryOneTime(3000))//三秒后重连 , 重连一次
                 * 2 retryPolicy(new RetryNTime(3,3000)) //每三秒重连一次 ,重连三次
                 * 3 retryPolicy(new RetryUntilElapsed(10000,3000)) //每3秒重连一次,总等待时间超过10秒后停止重连
                 *
                 * 4 基于传递的毫秒值传递的 ↓ 1000  Math.max(1,random.nextInt(1<<(retryCount +1))) 算出来的
                 * retryPolicy( new ExponentialBackoffRetry(1000,3))// 随着重连次数增加,重连的间隔也会增长
                 * 重连三次  每次重连过程中的间隔会越来越长
                 *//*
                .retryPolicy(exponentialBackoffRetry)
                //(命名空间)当我们通过连接对象去进行一系列操作时 他是以create作为父节点来操作的 如果不指定  那么久在根节点下创建
                .namespace("create")
                .build();//构建连接对象
        curatorFramework.start();//打开链接
        if (curatorFramework.isStarted() == true) {
            System.out.println("链接YES打开!!!");
        } else {
            System.out.println("链接NO打开!!!");
        }

    }

    *//**
     * 创建节点
     *//*
    @Test
    public void createNode() {
        connection();
        try {
            String s = curatorFramework.create()
                    .withMode(CreateMode.PERSISTENT) //节点类型
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE) //节点权限列表
                    .forPath("/curr02/curr022", "022value".getBytes(StandardCharsets.UTF_8));//当前节点的路径和 value

            System.out.println("创建的节点为:::" + s);
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 创建权限列表
     * 自定义权限列表
     *//*
    @Test
    public void createACL() {
        connection();
        try {
            List<ACL> acls = new ArrayList<>();
            Id id = new Id("ip", "192.168.60.130");
            acls.add(new ACL(ZooDefs.Perms.ALL, id));

            String s = curatorFramework.create()
                    .withMode(CreateMode.PERSISTENT) //节点类型
                    .withACL(acls) //节点权限列表
                    .forPath("/curr03", "03value".getBytes(StandardCharsets.UTF_8));//当前节点的路径和 value

            System.out.println("创建的节点为:::" + s);
            curatorFramework.close();
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 创建递归节点
     *//*
    @Test
    public void createRecursionNode() {
        connection();
        try {
            String s = curatorFramework.create()
                    .creatingParentsIfNeeded()  //*******父节点不存在 就创建
                    .withMode(CreateMode.PERSISTENT) //节点类型
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE) //节点权限列表
                    .forPath("/curr04/curr044", "044value".getBytes(StandardCharsets.UTF_8));//当前节点的路径和 value


            System.out.println("创建的节点为:::" + s);
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    *//**
     * 异步方式创建递归节点
     *//*
    @Test
    public void asyncCreateRecursionNode() {
        connection();
        try {
            curatorFramework.create()
                    .creatingParentsIfNeeded()
//                    .creatingParentContainersIfNeeded() //父节点不存在 就创建
                    .withMode(CreateMode.PERSISTENT) //节点类型
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)//节点权限列表
                    .inBackground(new BackgroundCallback() {  //*********异步创建节点
                        @Override
                        public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                            *//**
                             * curatorFramework 客户端与服务器建立连接的连接对象
                             * curatorEvent  事件对象
                             *//*
//                            System.out.println("连接对象的权限为:::"+new String(String.valueOf(curatorFramework.getACL())));
                            System.out.println("触发事件的节点路径:::" + curatorEvent.getPath());
                            System.out.println("触发事件的事件类型:::" + curatorEvent.getType());
                        }
                    }) //******** 异步创建方法
                    .forPath("/curr05/curr055", "055value".getBytes(StandardCharsets.UTF_8));//当前节点的路径和 value
            Thread.sleep(5000); //因为是异步所以让  主线程休眠

            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//*************************************************************SET (更新 ) 节点**********************************************************************

    *//**
     * 更新节点
     *//*
    @Test
    public void setNode() {
        connection();
        try {
            Stat stat = curatorFramework.setData()
                    .withVersion(12) //可以指定版本号  版本号必须和当前版本号一致
//                    .withVersion(-1)
                    .forPath("/curr02/curr022", "022刘荣华".getBytes(StandardCharsets.UTF_8));
            System.out.println("修改节点的版本号::" + stat.getVersion());
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    *//**
     * 异步更新节点
     *//*
    @Test
    public void asyncSetNode() {
        connection();
        try {
            curatorFramework.setData().withVersion(-1)
                    .inBackground(new BackgroundCallback() {
                        @Override
                        public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                            System.out.println("触发事件的节点路径:::" + curatorEvent.getPath());
                            System.out.println("触发事件的事件类型:::" + curatorEvent.getType());
                            System.out.println("版本号为" + curatorEvent.getStat().getVersion());
                        }
                    })
                    .forPath("/curr02/curr022", "022敦佳星".getBytes(StandardCharsets.UTF_8));
            Thread.sleep(6000);
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//*************************************************************delete (删除 ) 节点**********************************************************************

    *//**
     * 删除节点
     *//*
    @Test
    public void deleteNode() {
        connection();
        try {
            curatorFramework.delete()
                    .deletingChildrenIfNeeded()
                    .withVersion(0)
                    .forPath("/curr01");
            Thread.sleep(6000);
            System.out.println("节点已删除");
            curatorFramework.close();
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    *//**
     * 异步删除节点
     *//*
    @Test
    public void asyncDeleteNode() {
        connection();
        *//**
         * 注意 : 不写deletingChildrenIfNeeded 的时候 删除不报错  但是没有删除掉
         *//*
        try {
            curatorFramework.delete()
                    .deletingChildrenIfNeeded() //当有子节点时候可以用这个 直接删除
//                    .withVersion(-1) //写不写都一样 可以写-1
                    .inBackground(new BackgroundCallback() {
                        @Override
                        public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                            System.out.println("触发事件的节点路径:::" + curatorEvent.getPath());
                            System.out.println("触发事件的事件类型:::" + curatorEvent.getType());
                            System.out.println("版本号为" + curatorEvent.getStat().getVersion());
                        }
                    })
                    .forPath("/curr01");

            Thread.sleep(6000);
            System.out.println("节点已删除");

            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//*************************************************************getNode (获取节点 ) 节点**********************************************************************

    *//**
     * 获取(父)节点
     *//*
    @Test
    public void GetNode() {
        connection();
        Stat stat = new Stat();
        try {
            byte[] bytes = curatorFramework.getData().storingStatIn(stat).forPath("/curr01");
            System.out.println("数据为 ::: " + new String(bytes));
            System.out.println("数据版本号为:::" + stat.getVersion());
            curatorFramework.close();
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 异步获取节点
     *//*
    @Test
    public void asyncGetNode() {
        connection();

        try {
            byte[] bytes = curatorFramework.getData().inBackground(new BackgroundCallback() {
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                    System.out.println("触发事件的节点路径:::" + curatorEvent.getPath());
                    System.out.println("触发事件的事件类型:::" + curatorEvent.getType());
                    System.out.println("版本号为:::" + curatorEvent.getStat().getVersion());
                    System.out.println("数据为:::" + new String(curatorEvent.getData()));

                }
            })
                    .forPath("/curr01");

            Thread.sleep(6000);


            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 异步获取子节点
     *//*
    @Test
    public void getChildren() {
        connection();
        Stat stat = new Stat();
        try {
            List<String> list = curatorFramework.getChildren().storingStatIn(stat).forPath("/one");
            for (String s : list) {
                System.out.println("子节点为:::" + s);
                byte[] bytes = curatorFramework.getData().forPath("/one" + "/" + s);
                System.out.println("子节点数据为:::" + new String(bytes));
            }
            System.out.println("状态为:::" + stat);
            curatorFramework.close();
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 异步获取子节点
     *//*
    @Test
    public void asyncGetChildren() {
        connection();
        try {
            curatorFramework.getChildren()

                    .inBackground(new BackgroundCallback() {
                        @Override
                        public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                            System.out.println("触发事件的节点路径:::" + curatorEvent.getPath());
                            System.out.println("触发事件的事件类型:::" + curatorEvent.getType());
                            System.out.println("版本号为:::" + curatorEvent.getStat().getVersion());
                            System.out.println("子节点为:::0000000000");
                            List<String> children = curatorEvent.getChildren();
                            for (String child : children) {
                                System.out.println("子节点为:::" + child);
                            }


                        }
                    })
                    .forPath("/curr01");
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 异步获取子节点
     *//*
    @Test
    public void asyncGetChildrenData() {
        connection();
        try {
            curatorFramework.getChildren()
                    .inBackground(new BackgroundCallback() {
                        @Override
                        public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                            System.out.println("触发事件的节点路径:::" + curatorEvent.getPath());
                            System.out.println("触发事件的事件类型:::" + curatorEvent.getType());
                            System.out.println("版本号为:::" + curatorEvent.getStat().getVersion());
                            System.out.println("子节点为:::" + Arrays.asList(curatorEvent.getChildren()));

                        }
                    })
                    .forPath("/one");
            Thread.sleep(7000);
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //*************************************************************Exists (查看节点是否存在 ) 节点**********************************************************************

    *//**
     * 查看节点是否存在
     *//*
    @Test
    public void ExistsNode() {
        connection();
        try {
            if (curatorFramework.checkExists().forPath("/one") != null) {
                System.out.println("该链接存在!");
            } else {
                System.out.println("该链接不存在!!!");
            }

            Thread.sleep(7000);
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 异步查看节点是否存在
     *//*
    @Test
    public void asyncExistsNode() {
        connection();
        try {
            curatorFramework.checkExists().inBackground(new BackgroundCallback() {
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                    if (curatorEvent.getStat() != null) {
                        System.out.println("当前节点存在!!!");
                    } else {
                        System.out.println("当前节点不存在!!!");
                    }
                }
            })
                    .forPath("/one1");

            Thread.sleep(7000);
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //*************************************************************watcher (监听节点 ) 节点**********************************************************************

    *//**
     * 监听父节点
     * 多次变化
     *//*
    @Test
    public void watcherNode() {
        connection();
        try {
            NodeCache nodeCache = new NodeCache(curatorFramework, "/one");
            nodeCache.start();//启动监视器


            nodeCache.getListenable().addListener(new NodeCacheListener() {
                //当节点便变化时,回调的方法  getCurrentData 获取当前数据   Current:当前
                @Override
                public void nodeChanged() throws Exception {
                    System.out.println("节点的路径为:::" + nodeCache.getCurrentData().getPath());
                    System.out.println("节点的内容为:::" + new String(nodeCache.getCurrentData().getData()));
                }
            });

            Thread.sleep(100000);
            nodeCache.close();//关闭监视器
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    *//**
     * 监听子节点
     *//*
    @Test
    public void watcherChildrenNode() {
        connection();
        try {
            *//**
             * 1 curatorFramework
             * 2 /one
             * 3 true 可以获取节点数据   false 不可以获取节点数据
             *//*
            PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, "/one", true);
            pathChildrenCache.start();//启动监视器

            pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
                @Override
                public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                    System.out.println("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
                    System.out.println("节点的类型:::" + pathChildrenCacheEvent.getType());
                    System.out.println("节点的路径为:::" + pathChildrenCacheEvent.getData().getPath());
                    System.out.println("节点的数据为:::" + new String(pathChildrenCacheEvent.getData().getData()));
                    System.out.println("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");

                }
            });

            Thread.sleep(100000);
            pathChildrenCache.close();//关闭监视器
            curatorFramework.close();//关闭连接
            System.out.println("链接已关闭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //*************************************************************事务 事务**********************************************************************

    *//**
     * 默认事务
     * 默认情况下 第二步出错不会影响第一步的执行 (没有原子性)
     *//*
    @Test
    public void defaultOperation() {
        connection();
        try {
            String s = curatorFramework.create()
                    .creatingParentsIfNeeded()
//                    .creatingParentContainersIfNeeded() //*******父节点不存在 就创建
                    .withMode(CreateMode.PERSISTENT)
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).forPath("/four", "我是节点4".getBytes(StandardCharsets.UTF_8));
            Stat stat = curatorFramework.setData().withVersion(-1).forPath("/two", "我是二".getBytes(StandardCharsets.UTF_8));
            System.out.println("one:::" + s);
            System.out.println("two:::" + stat);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    *//**
     * 支持原子性
     * <p>
     *
     *     这个项目导入的项目是不可以运行这个方法的!!!
     * 依赖得导入正确  不然会报错java.lang.NoClassDefFoundError: org/apache/zookeeper/MultiTransactionRecord
     *//*
    @Test
    public void transaction() {
        connection();
        try {
            curatorFramework.inTransaction()
                    .create().forPath("/y", "y".getBytes())
                    .and().setData().forPath("/two", "我是二".getBytes())
                    .and()
                    .commit();

            curatorFramework.close();//关闭连接
            System.out.println("结束");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("错误信息为:::" + e.getMessage());
        }

    }*/

}

